﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using VsxTools.Properties;

namespace VsxTools.UtilityTypes
{
    public static class StringResolver<TPackage> where TPackage : Package
    {
// ReSharper disable once StaticFieldInGenericType
        private static readonly Dictionary<Assembly, Type> ResourceTypes =
            new Dictionary<Assembly, Type>();

        public static string Resolve(string toResolve)
        {
            if (string.IsNullOrEmpty(toResolve) || toResolve.Length < 2) return toResolve;

            if (toResolve.StartsWith("#"))
            {
                toResolve = toResolve.Substring(1);
                return toResolve.StartsWith("#") ? toResolve : ResolveInPackageResources(toResolve.Trim());
            }
            if (toResolve.StartsWith("$"))
            {
                toResolve = toResolve.Substring(1);
                return toResolve.StartsWith("$") ? toResolve : ResolveInResourcesClass(toResolve.Trim());
            }
            return toResolve;
        }

        public static bool ExistsInResourcesClass(string key)
        {
            Type resourceType = GetResourcesClassType();
            if (resourceType == null) return false;
            PropertyInfo propertyInfo = resourceType.GetProperty(key, BindingFlags.Static | BindingFlags.NonPublic);
            return propertyInfo != null;
        }

        public static string ResolveInResourcesClass(string key)
        {
            Type resourceType = GetResourcesClassType();
            if (resourceType == null) return Resources.ResourceNotFound;
            PropertyInfo propertyInfo = resourceType.GetProperty(key, BindingFlags.Static | BindingFlags.NonPublic);
            if (propertyInfo == null) return Resources.ResourceNotFound;
            return propertyInfo.GetValue(null, null).ToString();
        }

        public static bool ExistsInPackageResources(string key)
        {
            Guid packageGuid = GetPackageGuid();
            string resourceString;
            var resourceManager =
                (IVsResourceManager) Package.GetGlobalService(typeof (SVsResourceManager));
            if (resourceManager == null) return false;
            int result = resourceManager.LoadResourceString(ref packageGuid, -1, key, out resourceString);
            return result == VSConstants.S_OK;
        }

        public static string ResolveInPackageResources(string key)
        {
            Guid packageGuid = GetPackageGuid();
            string resourceString;
            var resourceManager =
                (IVsResourceManager) Package.GetGlobalService(typeof (SVsResourceManager));
            if (resourceManager == null) return Resources.PackageNotFound;
            int result = resourceManager.LoadResourceString(ref packageGuid, -1, key, out resourceString);
            if (result != VSConstants.S_OK) return Resources.PackageNotFound;
            return resourceString;
        }

        public static Type GetResourcesClassType()
        {
            Assembly callingAsm = typeof (TPackage).Assembly;
            Type resourceType;
            if (ResourceTypes.TryGetValue(callingAsm, out resourceType)) return resourceType;

            foreach (Type type in callingAsm.GetTypes())
            {
                if (type.GetCustomAttributes(typeof (CompilerGeneratedAttribute), false).Length > 0 && !type.IsVisible &&
                    type.Name == "Resources")
                {
                    ResourceTypes.Add(callingAsm, type);
                    return type;
                }
            }
            return null;
        }

        private static Guid GetPackageGuid()
        {
            return typeof (TPackage).GUID;
        }
    }
}
